Repository navigation
fix(functions): keep partial iteratee arguments out of keyword-bound slots - #448
Merged
dgilland merged 2 commits intoNov 11, 2026
Merged
Conversation
…slots `Partial._argcount` subtracted every keyword binding from the positional count, so a middle parameter bound by keyword still advertised a slot that a caller cannot fill. `map_` then passed the index into that slot and raised `TypeError: got multiple values for argument`. Positional capacity now ends just before the first keyword-bound slot. Slot indices are taken from `argspec.args` after skipping the implicit `self`/`cls` that `getfullargspec` reports but the signature-based `func_argcount` already excludes, so bound methods, classmethods and callable instances keep their previous arity for trailing bindings. Keyword-only parameters, `**kwargs`, varargs-only callables and callables without an inspectable signature keep their existing behavior. Adds regression tests for both partial directions: the reported failure through `map_` and `chain(...).map_()`, arity for trailing/middle/double bindings, implicit first parameters, bound positional arguments with a keyword slot, and the zero-argument case.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Partial._argcountnow ends positional capacity just before the first positional parameter bound bykeyword, for both
partialandpartial_right, and indexes those slots with the samesignature-based parameter list that
_argcountcounts, so bound methods, classmethods and callableinstances are not shifted by an implicit
self/cls.Symptom
The wrapper itself is fine (
wrapped(1) == 3); the failure only happens when pydash calls it as aniteratee.
Root cause
_argcountsubtracted the number of keyword-bound parameters from the positional parameter count,which is only correct when the keywords bind the trailing parameters:
With
increment=2bound, a three-parameter function still reports an arity of 2, socallitpasses
(element, index)and the index lands in the slot thatincrementalready occupies.Fix
Both corrections live in the same expression:
min(func_argcount - len(self.args), first_bound_slot - len(self.args)).argspec.argsafter skippinglen(argspec.args) - func_argcountleadingslots, because
getfullargspeckeeps an implicitself/clsthat the signature-basedfunc_argcountalready excludes. Without that alignment a bound method reports one slot too manyand re-raises
TypeErrorfor trailing keyword bindings, whichdevelopcurrently handles.Trailing keyword bindings keep their previous arity (
partial(transform, scale=2)._argcount == 2),keyword-only parameters and
**kwargsstill consume no positional slots, and callables without aninspectable signature keep the previous subtractive behavior.
Tests
tests/test_functions.pygains ten cases, parameterized over[_.partial, _.partial_right]whereboth directions agree:
map_andchain(...).map_(), plus the direct call as a control;the bound slot;
map_for both the trailing binding (already working ondevelop) and themiddle binding.
The reported
TypeErrorandassert 2 == 1fail ondevelopat1cf4661. The bound-method casesare preservation controls:
developalready returns[2, 6]there, and they guard the implicitselfalignment added here. Existingtest_partial_keyword_only_arguments_as_iterateeandtest_partial_variable_keyword_arguments_as_iterateecontinue to pass.Verification
pytest src/pydash tests --cov=pydash --ignore=tests/pytest_mypy_testing— 3322 passed, 100%coverage on CPython 3.13.15.
pytest tests/test_functions.py— 144 passed on CPython 3.10.21 and 3.14.9.ruff format --check,ruff check,mypy src/pydash tests tasks.py— clean.sphinx-build -q -W -b html docs docs/_build/html— clean.Notes
This addresses the scope question in #416, where the maintainer replied that fixes and improvements
are welcomed. The change is limited to the arity calculation; no public signature, units, dtype or
output-shape behavior changes.
Prepared with AI agent assistance; every command and output above was executed locally against this
branch, and the patch was additionally reviewed by a second automated reviewer. No independent human
code review is claimed.